package com.zhonglz.util.sign.ofd;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.security.cert.X509Certificate;
import java.util.List;

import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPrivateKey;
import org.ofdrw.core.basicType.ST_Box;
import org.ofdrw.gm.ses.v4.SESeal;
import org.ofdrw.reader.OFDReader;
import org.ofdrw.reader.keyword.KeywordExtractor;
import org.ofdrw.reader.keyword.KeywordPosition;
import org.ofdrw.sign.NumberFormatAtomicSignID;
import org.ofdrw.sign.OFDSigner;
import org.ofdrw.sign.SignMode;
import org.ofdrw.sign.StandFormatAtomicSignID;
import org.ofdrw.sign.signContainer.SESV4Container;
import org.ofdrw.sign.stamppos.NormalStampPos;
import org.ofdrw.sign.stamppos.RidingStampPos;
import org.ofdrw.sign.stamppos.Side;
import org.ofdrw.sign.verify.OFDValidator;
import org.ofdrw.sign.verify.container.SESV4ValidateContainer;

import com.zhonglz.util.cert.sm2.CertificateUtils;
import com.zhonglz.util.minio.MinioProperties;
import com.zhonglz.util.minio.MinioUtils;
import com.zhonglz.util.result.ResultUtils;
import com.zhonglz.util.tools.ObjectUtils;


/**
 * @author Saxon
 * @Date   2021年6月11日
 */
public class SignSm2Ofd {

	/**
	 * 骑缝章方法 右侧
	 * @param orgOfdPath   原文档地址
	 * @param signOfdPath  文档保存地址
	 * @param certPath     证书地址
	 * @param sealPath	   印章地址
	 * @param certPwd	   证书密码
	 * @return
	 */
	public static ResultUtils signRideRight(String orgOfdPath,String signOfdPath,String certPath,String sealPath,String certPwd) {
        //获取到证书对象及证书私钥
		try {
	        byte[] certByte = MinioUtils.getObjectBytes(certPath);
	        byte[] sealByte = MinioUtils.getObjectBytes(sealPath);
	        InputStream orgOfdIn = MinioUtils.getObject(orgOfdPath);
	        ByteArrayOutputStream output = new ByteArrayOutputStream();
	        BCECPrivateKey prvKey = CertificateUtils.getBCECPrivateKeyFromPfx(certByte, certPwd);
	        X509Certificate signCert = CertificateUtils.getX509CertificateFromPfx(certByte, certPwd);
	        SESeal seal = BuildSESeal.sealBuild(signCert, sealByte, prvKey);
	        // 1. 构造签名引擎
	        OFDReader reader = new OFDReader(orgOfdIn);
            OFDSigner signer = new OFDSigner(reader, output,new StandFormatAtomicSignID() );
            SESV4Container signContainer = new SESV4Container(prvKey, seal, signCert);
            // 2. 设置签名模式
            signer.setSignMode(SignMode.WholeProtected);
            // 3. 设置签名使用的扩展签名容器
            signer.setSignContainer(signContainer);
            // 4. 设置显示位置
            signer.addApPos(new RidingStampPos(Side.Right, 40.0, 40, 40));
            // 5. 执行签名
            signer.exeSign();
            reader.close();
            signer.close();
            // 6. 关闭签名引擎，保存文档
	        if(output.size() <= 0 ) {
	        	return new ResultUtils(ResultUtils.CODE_ERROR,"签章文档保存失败,请稍后重试!");
	        }
	        MinioUtils.putObject(signOfdPath,new ByteArrayInputStream(output.toByteArray()));
	        return new ResultUtils(ResultUtils.CODE_SUCCESS,"签章成功!",signOfdPath);
		}catch (Exception e) {
			e.printStackTrace();
			return new ResultUtils(ResultUtils.CODE_EXCEPTION,e.getMessage());
		}
	}
	
	
	/**
	 * 
	 * 关键字签章
	 * @param orgOfdPath   原文档地址
	 * @param signOfdPath  文档保存地址
	 * @param certPath     证书地址
	 * @param sealPath	   印章地址
	 * @param certPwd	   证书密码
	 * @param keyword	   关键字
	 * @return
	 */
	public static ResultUtils signKeyWord(String orgOfdPath,String signOfdPath,String certPath,String sealPath,String certPwd,String[] keyword) {
        //获取到证书对象及证书私钥
		try {
	        byte[] certByte = MinioUtils.getObjectBytes(certPath);
	        byte[] sealByte = MinioUtils.getObjectBytes(sealPath);
	        InputStream orgOfdIn = MinioUtils.getObject(orgOfdPath);
	        ByteArrayOutputStream output = new ByteArrayOutputStream();
	        BCECPrivateKey prvKey = CertificateUtils.getBCECPrivateKeyFromPfx(certByte, certPwd);
	        X509Certificate signCert = CertificateUtils.getX509CertificateFromPfx(certByte, certPwd);
	        SESeal seal = BuildSESeal.sealBuild(signCert, sealByte, prvKey);
	        OFDReader reader = new OFDReader(orgOfdIn);
            List<KeywordPosition> positionList = KeywordExtractor.getKeyWordPositionList(reader, keyword);
            // 保证有且只有四个关键字返还
            if (positionList.size() > 0) {
                OFDSigner signer = new OFDSigner(reader, output, new NumberFormatAtomicSignID());
                SESV4Container signContainer = new SESV4Container(prvKey, seal, signCert);
                // 2. 设置签名模式
                signer.setSignMode(SignMode.ContinueSign);
                // 3. 设置签名使用的扩展签名容器
                signer.setSignContainer(signContainer);
                for (KeywordPosition position : positionList) {
                    // 4. 中心点对齐签署
                    ST_Box box = position.getBox();
                    signer.addApPos(new NormalStampPos(position.getPage(), box.getTopLeftX() + box.getWidth() / 2 - 20,
                            box.getTopLeftY() + box.getHeight() / 2 - 20, 40, 40));
                }
                // 5. 执行签名
                signer.exeSign();
                reader.close();
                signer.close();
                // 6. 关闭签名引擎，生成文档。
                if(ObjectUtils.isEmpty(output)) {
    	        	return new ResultUtils(ResultUtils.CODE_ERROR,"签章文档保存失败,请稍后重试!");
    	        }
    	        MinioUtils.putObject(signOfdPath,new ByteArrayInputStream(output.toByteArray()));
    	        return new ResultUtils(ResultUtils.CODE_SUCCESS,"签章成功!",signOfdPath);
            }else {
            	return new ResultUtils(ResultUtils.CODE_ERROR,"签章失败,签章关键字不能为空!");
            }
		}catch (Exception e) {
			e.printStackTrace();
			return new ResultUtils(ResultUtils.CODE_EXCEPTION,e.getMessage());
		}
	}
	
	
	
	/**
	 * 
	 * 关键字签章
	 * @param orgOfdPath   原文档地址
	 * @param signOfdPath  文档保存地址
	 * @param certPath     证书地址
	 * @param sealPath	   印章地址
	 * @param certPwd	   证书密码
	 * @param NormalStampPos 位置信息        
	 * @return
	 */
	public static ResultUtils signBy(String orgOfdPath,String signOfdPath,String certPath,String sealPath,String certPwd,NormalStampPos apPos) {
        //获取到证书对象及证书私钥
		try {
	        byte[] certByte = MinioUtils.getObjectBytes(certPath);
	        byte[] sealByte = MinioUtils.getObjectBytes(sealPath);
	        InputStream orgOfdIn = MinioUtils.getObject(orgOfdPath);
	        ByteArrayOutputStream output = new ByteArrayOutputStream();
	        BCECPrivateKey prvKey = CertificateUtils.getBCECPrivateKeyFromPfx(certByte, certPwd);
	        X509Certificate signCert = CertificateUtils.getX509CertificateFromPfx(certByte, certPwd);
	        SESeal seal = BuildSESeal.sealBuild(signCert, sealByte, prvKey);
	        OFDReader reader = new OFDReader(orgOfdIn);
            // 保证有且只有四个关键字返还
                OFDSigner signer = new OFDSigner(reader, output, new NumberFormatAtomicSignID());
                SESV4Container signContainer = new SESV4Container(prvKey, seal, signCert);
                // 2. 设置签名模式
                signer.setSignMode(SignMode.ContinueSign);
                // 3. 设置签名使用的扩展签名容器
                signer.setSignContainer(signContainer);
                signer.addApPos(apPos);
                // 5. 执行签名
                signer.exeSign();
                reader.close();
                signer.close();
                // 6. 关闭签名引擎，生成文档。
                if(ObjectUtils.isEmpty(output)) {
    	        	return new ResultUtils(ResultUtils.CODE_ERROR,"签章文档保存失败,请稍后重试!");
    	        }
    	        MinioUtils.putObject(signOfdPath,new ByteArrayInputStream(output.toByteArray()));
    	        return new ResultUtils(ResultUtils.CODE_SUCCESS,"签章成功!",signOfdPath);
		}catch (Exception e) {
			e.printStackTrace();
			return new ResultUtils(ResultUtils.CODE_EXCEPTION,e.getMessage());
		}
	}
	
	
	
	
	
	
	
	
	/**
	 * 
	 * @param signOfdPath  签章后的文件
	 * @return
	 */
	public static ResultUtils verifySign(String signOfdPath) {
	   try {
		  InputStream signOfdIn = MinioUtils.getObject(signOfdPath);
		  OFDReader reader = new OFDReader(signOfdIn);
		  OFDValidator validator = new OFDValidator(reader);
          validator.setValidator(new SESV4ValidateContainer());
          validator.exeValidate();
          reader.close();
          validator.close();
          return new ResultUtils(ResultUtils.CODE_SUCCESS,"验证通过");
	    }catch (Exception e) {
	    	e.printStackTrace();
	    	return new ResultUtils(ResultUtils.CODE_ERROR, "验证失败:原因:"+e.getMessage());
		}
	}
	
	
	
	
	
	
	
	
	public static void main(String[] args) {
		System.out.println(MinioProperties.bucketName);
		String pfxPath = "/cert/50d51accc8964dbaaef6f0d6eaa42778.pfx";
		String pdfPath = "/file/c8c9519a51e94d2a8d2c116b2f52375a.pdf";
		String sealPath = "/file/cbb3c8f485d840a682f03c568e2ceb52.png";
		String outPdfPath = "/file/ceshi.pdf";
		signRideRight(pdfPath,outPdfPath,pfxPath,sealPath,"123456");
		
	}
	
	
	
}
